{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "nbsphinx": "hidden"
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "pd.set_option(\"display.max_rows\", 5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Backends\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Quick examples"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### pandas (fast grouped) _"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><p>(grouped data frame)</p><div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>cyl</th>\n",
       "      <th>mpg</th>\n",
       "      <th>hp</th>\n",
       "      <th>avg_mpg</th>\n",
       "      <th>hp_per_mpg</th>\n",
       "      <th>demeaned</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>6</td>\n",
       "      <td>21.0</td>\n",
       "      <td>110</td>\n",
       "      <td>19.742857</td>\n",
       "      <td>5.238095</td>\n",
       "      <td>-12.285714</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>6</td>\n",
       "      <td>21.0</td>\n",
       "      <td>110</td>\n",
       "      <td>19.742857</td>\n",
       "      <td>5.238095</td>\n",
       "      <td>-12.285714</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>30</th>\n",
       "      <td>8</td>\n",
       "      <td>15.0</td>\n",
       "      <td>335</td>\n",
       "      <td>15.100000</td>\n",
       "      <td>22.333333</td>\n",
       "      <td>125.785714</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31</th>\n",
       "      <td>4</td>\n",
       "      <td>21.4</td>\n",
       "      <td>109</td>\n",
       "      <td>26.663636</td>\n",
       "      <td>5.093458</td>\n",
       "      <td>26.363636</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>32 rows × 6 columns</p>\n",
       "</div></div>"
      ],
      "text/plain": [
       "<pandas.core.groupby.generic.DataFrameGroupBy object at 0x11882d320>"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# pandas fast grouped implementation ----\n",
    "from siuba.data import cars\n",
    "from siuba import _\n",
    "from siuba.experimental.pd_groups import fast_mutate, fast_filter, fast_summarize\n",
    "\n",
    "fast_mutate(\n",
    "    cars.groupby('cyl'),\n",
    "    avg_mpg    = _.mpg.mean(),          # aggregation\n",
    "    hp_per_mpg = _.hp / _.mpg,          # elementwise    \n",
    "    demeaned   = _.hp - _.hp.mean(),    # elementwise + agg\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### SQL _"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><pre># Source: lazy query\n",
       "# DB Conn: Engine(sqlite:///:memory:)\n",
       "# Preview:\n",
       "</pre><div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>cyl</th>\n",
       "      <th>avg_mpg</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>4</td>\n",
       "      <td>26.663636</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>6</td>\n",
       "      <td>19.742857</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>8</td>\n",
       "      <td>15.100000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div><p># .. may have more rows</p></div>"
      ],
      "text/plain": [
       "# Source: lazy query\n",
       "# DB Conn: Engine(sqlite:///:memory:)\n",
       "# Preview:\n",
       "   cyl    avg_mpg\n",
       "0    4  26.663636\n",
       "1    6  19.742857\n",
       "2    8  15.100000\n",
       "# .. may have more rows"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from siuba import _, mutate, group_by, summarize, show_query\n",
    "from siuba.sql import LazyTbl\n",
    "from sqlalchemy import create_engine\n",
    "\n",
    "# create sqlite db, add pandas DataFrame to it\n",
    "engine = create_engine(\"sqlite:///:memory:\")\n",
    "cars.to_sql(\"cars\", engine, if_exists=\"replace\")\n",
    "\n",
    "# define query\n",
    "q = (LazyTbl(engine, \"cars\")\n",
    "    >> group_by(_.cyl)\n",
    "    >> summarize(avg_mpg=_.mpg.mean())\n",
    ")\n",
    "\n",
    "q"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SELECT cars.cyl, avg(cars.mpg) AS avg_mpg \n",
      "FROM cars GROUP BY cars.cyl\n"
     ]
    }
   ],
   "source": [
    "res = show_query(q)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Supported methods\n",
    "\n",
    "The table below shows the pandas methods supported by different backends. Note that the regular, ungrouped backend supports all methods, and the fast grouped implementation supports most methods a person could use without having to call the (slow) `DataFrame.apply` method.\n",
    "\n",
    "> 🚧This table is displayed a bit funky, but will be cleaned up!"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/html"
   },
   "source": [
    "<style>\n",
    "\n",
    "iframe.method-support {\n",
    "  border: none;\n",
    "  width: 100%;\n",
    "  height: 1800px;\n",
    "  \n",
    "}\n",
    "</style>\n",
    "<iframe class=\"method-support\" src=\"http://mchow.com/siuba-doc-method-table/\"></iframe>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## pandas (ungrouped)\n",
    "\n",
    "In general, ungrouped pandas DataFrames do not require any translation.\n",
    "On this kind of data, verbs like `mutate` are just alternative implementations of methods like `DataFrame.assign`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>g</th>\n",
       "      <th>x</th>\n",
       "      <th>y</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>a</td>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>a</td>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>b</td>\n",
       "      <td>3</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   g  x  y\n",
       "0  a  1  2\n",
       "1  a  2  3\n",
       "2  b  3  4"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from siuba import _, mutate\n",
    "\n",
    "df = pd.DataFrame({\n",
    "    'g': ['a', 'a', 'b'],    \n",
    "    'x': [1,2,3],\n",
    "    })\n",
    "\n",
    "df.assign(y = lambda _: _.x + 1)\n",
    "\n",
    "mutate(df, y = _.x + 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Siuba verbs also work on grouped DataFrames, but are not always fast. They are the potentially slow, reference implementation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><p>(grouped data frame)</p><div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>g</th>\n",
       "      <th>x</th>\n",
       "      <th>y</th>\n",
       "      <th>z</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>a</td>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>-0.5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>a</td>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "      <td>0.5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>b</td>\n",
       "      <td>3</td>\n",
       "      <td>4</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div></div>"
      ],
      "text/plain": [
       "<pandas.core.groupby.generic.DataFrameGroupBy object at 0x1188709b0>"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mutate(\n",
    "    df.groupby('g'),\n",
    "    y = _.x + 1,\n",
    "    z = _.x - _.x.mean()\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## pandas (fast grouped)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that you could easily enable these fast methods by default, by aliasing them at import.\n",
    "\n",
    "```python\n",
    "from siuba.experimental.pd_groups import fast_mutate as mutate\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Architecture (1)\n",
    "\n",
    "Currently, the fast grouped implementation puts all the logic in the verbs. That is, `fast_mutate` dispatches for DataFrameGroupBy a function that handles all the necessary translation of lazy expressions.\n",
    "\n",
    "See TODO link this ADR for more details."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## SQL\n",
    "\n",
    "###  Architecture (2)\n"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "jupyter": {
     "source_hidden": true
    },
    "raw_mimetype": "text/html"
   },
   "source": [
    "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" width=\"811px\" viewBox=\"-0.5 -0.5 811 623\" content=\"&lt;mxfile host=&quot;app.diagrams.net&quot; modified=&quot;2020-04-29T22:00:18.274Z&quot; agent=&quot;5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36&quot; etag=&quot;Tp_dICBLt3o_wYUzd_51&quot; version=&quot;13.0.2&quot; type=&quot;google&quot; pages=&quot;3&quot;&gt;&lt;diagram id=&quot;prtHgNgQTEPvFCAcTncT&quot; name=&quot;general&quot;&gt;5Zpbc+I2FIB/DTPJgz2+Ex4TJ9l2p+l2Sjrd3ZeMwALUGMuVxWLy6/cIWSDZJgHipGTqh4x0dLF89J2LRHp+PC8/MZTP7miC057nJGXPv+55Xv8igr9CsJKCoB9IwZSRRIrcrWBInnAldCrpgiS4MDpySlNOclM4plmGx9yQIcbo0uw2oan51hxNcUMwHKO0Kf2bJHwmpZHjbOW/YDKdVW8OVMMcqb6VoJihhC41kX/T82NGKZeleRnjVKhOqUWOu93RulkXwxnfZ8DN/Zer/sz1+J+Lyd3D3eenOUZWNcsPlC6q7+15UQrzXY2gMBUFJZhQeA98Bl9Vqon+XVDVYBXrjbuEDm6Ql9tGNcsPzEZnIzR+xFnS82LoR3NXFmzbVpLfz9Xb4DvkC81FgFhbmGesx+O4FPIZn6cgcKFYcEYfcUxTykCS0QyL9ZI0rYlQSqYZVMegS8zkcjkBCC6rhjlJEvGaq+WMcDzM0Vi8cwnEg4zRRZZgoWZnsyx9X5SSYU5caqJqnz5hOsecraBL1Trw5YiVgk1Wl1v+fIXZTGNPkYYq5KebibdYQKEi4wBK/AYldkKKHPHx7OxK7ul5YzdAeCnsT6g1RUVBxube7NQTTgyL3Kkly7HB3AJDVUHYUFXYoiklYzhFnPwwTb1NfdUi/qBkbQSlUri5URe1DSjogo1xNUg3zdo8bjCwI/0xp3Wj2rwcsSnmjXlB3WildctFh2L38t2L2ntcw4NAQc644+ONsVZgLpFOJgXmvTp5m108HsZBA8ZrxFETvzSFELHLZDUOUZHLuDEhpTDiLgw4NBW74W2pR5AmlvV97syAwxY3f6C54pLwr8LF2WFV+6a1XJeV91tXVqqSweK1QaL6TW/bDlvX1LidOyAN6pkP9SrFSwt5rmO0p7N5H0/iejVigiNdiedcGBNtAsULvqMr61Rp26tQOxKbYxB9B9QGJ05aeGTQ6teix6A20VuT1pa7vhNpO6l52e8EJ0WD31EG44dCg8ckLZ3h0ExSuzm5PNiQXMC3gMB5sEc7DygneRgRSxxWi2o5MR6c2AS+GV5ajiYqi3yfo4kb/F/ijbt3ahOelIsJfdPF9I90MaFnoueG7+xgog5IU8RovDh2P3wWmQ2ergHnltXus+jwY0azwA9rUWhzjXhwQAtqaVLdgx1N218FZl9G/4gzp+ekaIRTM1oVOcpao9Xa21uFdPciXmWUzZHgdr3Zjrhdm67dvzWWEUV0YtPRmSduSRx5yWaUw/C8GfBqYbOa61rvCKcK8XQ79krdDr50A7hDLBWnh+OUZI9KuX41fSGbnjV1mSKbvkGzcjPEvnC9oAd4WEUMz+3tm1wTum3BuO2esH623CMYQ1Xj9j/jOAx1dnWmO+Y4RmLTX0ncb+hpZeEyZxgiAc0K6wxySQsySQvyyPN9OAzejMNbeOK4Gw5PHMTD9r8F2K6AHK7mI5pCTvDcEaJjgsIPQVDgt99Ef0iCXuN9jqdPD+u+00LfPUNZAekVzHBghG1gqaYi2dSiOWZQAjj3wTF6Qxzj+CbqBkc3evn+fvBmNDaOI9bX8vN9cDOOv99+J3j460NxP2r55bYgC7vgjOQPxcbRnOSlRBcOw9kj5HgtW3TERQRUt7/Sy/x++58O/s1P&lt;/diagram&gt;&lt;diagram id=&quot;K_BTHCAaedgZikr9X4cn&quot; name=&quot;backend-pandas&quot;&gt;1VjLUtswFP0az9BFPH4mYRlCoZu2zGSmLStGsZVYRbZcWSF2v74SkmIrtsmDkAILRjp6Xd977j1SLH+alrcU5MlXEkNseU5cWv615Xmj8ZD/F0AlgWAUSGBJUSwhtwZm6C9UoKPQFYphYUxkhGCGchOMSJbBiBkYoJSszWkLgs1Tc7CELWAWAdxGf6KYJRIdOk6Nf4FomaiTx3ogBXquAooExGTdgPzPlj+lhDDZSsspxMJ12i3YuZtU05vf6z9OeQnSIHmc/BjIzW4OWbL5AgozdvTWs+9Xk6/hgt6WecLuhj/my2mgljhPAK+UuyxviPkhV3PeWIqGBhaEH869wCrl2eGfFdEDg+I57hM+wQ3ysh7UuzxBOr+Yg+gRZrHlTfk8kruyYdu2Rr590qfx75AHmkZwuGGYZ9jjMVgKPGEp5oDLmwWj5BFOCSaUIxnJoLAXYbwFAYyWGe9G3MGQSnMZ4hyaqIEUxbE45mqdIAZnOYjEmWueMByjZJXFULjZ2Zi1M1gqqOIgWDaYqoJ3C0kKGa34FDV66csVlSaw7K5rTvuaukmDz5q9QKXRcrNxzRXeUHQ5gDpuizp2jIocsCi5uJKB/tQKEQcnIqeFrzEoChSZATvMeTA2Ur/XdQPH9gInMPwXhC3/hR3u0xiFGDD0ZNaULp8qI+4Iek6XUkfBjN54KyoFWdEIqkXNJN7axw0u7WHjL/SMbd3h1r4M0CVkrX15DEDVmJaLCUW/+e7YNN91jVrDG3LHno831g4C00SyWBSQWdt03ETxeIaGHcXtQD5yGtLql8hsO9Tde5Xoz53r0uhVRxUBGaWXcs3Zk/DnYbN/Ijb7oXDrMQQ+FUWGvfr3Orl7sIElKi8HnAd73qtq71LBhIkzZdS+d4+D5Szwx7v0TFeZ8+jZ6P9VC1gi1ljGe/d6R96uF4nOcRVGZuTuRNhdifaV3vNUotA3K9HoyEoUeiYb3fC8dWh8AvJpEjUo5Nij8EUWbRjrGnyt6XsSfdvJPveDCmHgh1sCtnn2HqyFgcnkVqF7YwZe9iohv9NnnUr4rCSDQkqJ0MKM0BTgthpeAwZuKEhhQwflrj06aOpRl2Id/WbYX6E0R3RAgg6F6npxBW/24up/rb8+RlMgDPhA4dl+ELtdN4jzxqf9JJ5V6ZxgXqrfpQsDv/tZ9x9d6LdcWKCVzW/BKH8o+pz5Pq7NbxYlZw+ie6e5KvNu/YOmlJb6R2H/8z8=&lt;/diagram&gt;&lt;diagram id=&quot;t5tLW42HWwBpjyBLeSh1&quot; name=&quot;backend-sql&quot;&gt;7Vxdc+K4Ev01VGW2Csq2sIHHQDKzW5XZm7ukamf3hRK2AG2M5ZHFEObXX0mWvyQDhuBkUxceEtyW23b3Oa1WS6IDJuuXLxTGq68kQGHHsYKXDrjrOI4NbIv/E5JdKhmMlGBJcaAaFYIp/omUMGu2wQFKKg0ZISHDcVXokyhCPqvIIKVkW222IGH1rjFcIkMw9WFoSv/EAVul0pFlFfJfEV6u1J09V51Yw6ytEiQrGJBtSQTuO2BCCWHpt/XLBIXCdplZHsCMRtMvoxF4HM/XT9PhP8/33VTZ51Muyd+AoohdWHU/1f0DhhtlrwkUl8kXZrvMiCu2Dvk3uwPGDR9GPfQPRBl6KXlCPdwXRNaI0R1vos46QNlZ4Qx4Tnq8Lbw2sHrqgVcllwHVECqkLHPdhTn4F2WRE6zTtw3rcBDEaOYfsZF4a8wb3YZ4GXHZnDBG1vwEioJbgWkuIzGKpIQ/6Td+bPUsq58J/pICG+SCO2ElKz/aZUcvmH1TNxXf0+tcdVRcJA52ZQ2PiGJuJERzYfAZC+vIowAmKxSc5fCEbKiPGkCOQbpEhxS6aTsUVPi9Fz9dqweGw1EFQ/bIgNBQoYyiEDL8oxok6hCkbvhIMH/9Aq2jHIoZXp1BzxmOio9X1ZkaRqkp81TTDAanak4taWjmQIO7UrNYNEj2vxLQCTgYagxKNWpXZ+rJYpEg1tE5lzvqFTR0DBoyCv1nScPZFkeB6CQuREdFqIJEf5XodYBQ4iIOQcu2qxwG7ugYhz8IHwen8ZG/uj2sAtnOutLL8xG4OnhH59Gvb7BAU3QhtvFEo3Iftz/6d7DNNdl2k+YEXJ/1gBPWccfJ9xD2/sN5NQnhJkEd9+6TQUABlAc45+kkGJfICBUJfQ5fAXeDnWscBELHmKIE/4RzqU+wQJmUK3fH/I7NqZAHED0ZybNOdZdKZlcPam/UBxdBbBdo5HB75RjPP1WN7XncAYbHTWcWkXIeEv85DVEq27c9I2KVHF5kONXI6PTtcyLjaeHvaFSzhw3DWilm2d5lgpanxZq+B84LWt5IVzRsFLQuhiBzGHEIQRGJkIYRbv2paksoW5EliWB4X0jPynQv3FOChkh5LSosrQca2r2BfSYwdIS57fRm7lB/Zmd/b3Yx1LnHUaf3ITUdUYgW7FCSGIo+bMzzzSUlmyiYkJBQqRws5Ic3WZCIZbHwBOBltKnvhE4ZPGcYbgy9V42LHe8ihqfpEP5jW/5tDT/4f4izTQcar4yzesxynTOHDO8VZF0ATnourX1LQXn40YPy4IMG5dGHD8oXs/ybGj6b6CgZfvo9fJqbFeJki9chlDFZmkidaTQqZiTmUn+Fw+AB7shGGDJh3A3Z0XhFKP7J1cLMpfw0zfzgeJUWU3GlAoEEBXrMvGNroq/wpdLwASZMCXwShjBO8Dx/jTWPdDgaK6yc0Tk093G/GtwcYNZ67WxYVJktyNLrywOhZrpA9XW3AgiiZnIfcfugjsiggOTGYhP5SdrgDvusdIZxBGUX9p4kG4qTJFYXlQsyUxSKGTT3rtRQsDSezXdp66dNXFVDA0T3nuVWCLm3ZwJ64rzSXzTodqVrkwQFYqxN+B9RKnqiCD0QDt5SU7qeQcZoSSKrt8lmrssDnMSQ+auZHyZlBSjZhCwVarziiGES75Q8oywgqeRngcNQEx3pY1Km8WfwcbR8kG3u+oXkDwUlISL82kUoc60VDgJZQaaEQba3ajXm4JuIfEo4acKP7eJYlrRinpZNSMTfBWJJGMQ9sEWCc42p1DxeZuTxmnHHHvTb4o5ZdTTcHGLpvtTN2VyufZaP8xqjcuqT8Pld1zYcD0zHgxony07xkSSYYVLuRc2S5fv41zIL77UOHrblXrPECOOYD1V4bLnJwoqoL/d6vU/8n4o3qhstQgaJdze//PK85d1M8mlPo2KKtlS3ruhNxUWgNSaT5IVS/8Tp3FrqbymoIh4URehEwYx3grMIrlFyY5bAr4Hp1cAdNgPuyGkJuWap40+JkT9QHEKfp2rXJK/VJE8bWo+AiYdhXU/Vb6unMksw3EKbdaTysa88rnEyZinZRJ7bk5LV5GGFKA1FM58hQ1hO/a4h5yDivMaIO5AK1QFs2Ba+GtRPronQmc617Zo8qNa7LTm3rkbD39bi2lckuGG7GKm0Rny9kvvi/q9JJ+r873gtAcAc5mgD5ms28XbZhNOvqRnVwqG1mpE5LgolDmQMCKoFoWrBJC0NoUqDFaeS1mJMSLivuJIWfWSgqSuzlE5f49DBwvWHSzIarNe4JhlnOvfdkwxzWYRPEWRoJkNLWhlJRMl1T2HkSvYL46Fh0jFsq4Zhm4gQnhbjRxRdSxjtJh362ry6fS35gsJK0gFam6gyi1pLAQTsz35gHlXLI5DSZNA1LhwEhtsYGQeygFogtDUYsRssJ7qmAee6123I89bmXMxKkgzaxeSGMRMiVnVlkx1q1uNA6yxmHNOatztJu9Q6w4s0X3lSjZ4qEak6EZ12STKrkbfKyipJR2wbpWvIDPVcEAoQiHv3xFQ8FyyFQD3YgZstDWWzmZgXwgytZ7Oa66/h87L88mrS7Dp+2YO2+lHXHL1ntf2bNK/WfP4W22jtarrh1ZQ47BortZZsuGayASmF0RK9m43A8N9mI7MuvN5wRvL86zOPBTKsfU42a5628sz23ezmesft5r6p3WqGumKJQDHDZkmpWtnkimhbu1ftHTaLqovy/VCdI3uhjq/crmzAOg0DR9dkZ6Hu+H4q5esTtm1bg2yjvcJVt719os6gCmFbX6vdeJu2e0RRS/tE7eo+UaO9DQ62f8d9pWY6KrlaTH3rXJXz5/v3l145e4yzXnucdb2sWtU+Z4G+1FffGtt4b7dzRNGFONs/zMGPw1nP7F+LZXvHspArKQ+lem2QcmCBN+tIgdaRAutcUuq/3KAruhApvQ9ISm+KcX+U/A5+nXX//hvSb791J11zu0lWxRDF+godve8bkp3oJrLCLoooHM4vxcms5DH97wM/d0v9FWbIZxuKMr1iFCJVpw0N0qtSRks/8gA3jCRqN1F+95qfcmhG0f2DQi3RqqFOXkmorg3YT52mg5taP5u7SX4nLPfJnBbu0CUic8rTKXHgr9B6Z7hNLpTuiAoTE57YCr9PYyjD15bCuOrSzAX9vdUnrURVrfJ6LbpuoCUIdt3A1Krx3RmVIX5Y/ORbSunid/PA/f8A&lt;/diagram&gt;&lt;/mxfile&gt;\" onclick=\"(function(svg){var src=window.event.target||window.event.srcElement;while (src!=null&amp;&amp;src.nodeName.toLowerCase()!='a'){src=src.parentNode;}if(src==null){if(svg.wnd!=null&amp;&amp;!svg.wnd.closed){svg.wnd.focus();}else{var r=function(evt){if(evt.data=='ready'&amp;&amp;evt.source==svg.wnd){svg.wnd.postMessage(decodeURIComponent(svg.getAttribute('content')),'*');window.removeEventListener('message',r);}};window.addEventListener('message',r);svg.wnd=window.open('https://app.diagrams.net/?client=1&amp;lightbox=1');}}})(this);\" style=\"cursor:pointer;max-width:100%;max-height:623px;\"><defs><clipPath id=\"mx-clip-4-252-182-174-0\"><rect x=\"4\" y=\"252\" width=\"182\" height=\"174\"/></clipPath><clipPath id=\"mx-clip-4-434-182-92-0\"><rect x=\"4\" y=\"434\" width=\"182\" height=\"92\"/></clipPath><clipPath id=\"mx-clip-364-506-172-84-0\"><rect x=\"364\" y=\"506\" width=\"172\" height=\"84\"/></clipPath><clipPath id=\"mx-clip-364-598-172-26-0\"><rect x=\"364\" y=\"598\" width=\"172\" height=\"26\"/></clipPath><clipPath id=\"mx-clip-364-262-172-84-0\"><rect x=\"364\" y=\"262\" width=\"172\" height=\"84\"/></clipPath><clipPath id=\"mx-clip-364-354-172-82-0\"><rect x=\"364\" y=\"354\" width=\"172\" height=\"82\"/></clipPath><clipPath id=\"mx-clip-654-375-152-26-0\"><rect x=\"654\" y=\"375\" width=\"152\" height=\"26\"/></clipPath><clipPath id=\"mx-clip-654-409-152-170-0\"><rect x=\"654\" y=\"409\" width=\"152\" height=\"170\"/></clipPath></defs><g><rect x=\"190\" y=\"344\" width=\"70.4\" height=\"32\" fill=\"#ffffff\" stroke=\"#000000\" pointer-events=\"all\"/><g transform=\"translate(-0.5 -0.5)\"><switch><foreignObject style=\"overflow: visible; text-align: left;\" pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"><div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 360px; margin-left: 225px;\"><div style=\"box-sizing: border-box; font-size: 0; text-align: center; \"><div style=\"display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; \">Call</div></div></div></foreignObject><text x=\"225\" y=\"364\" fill=\"#000000\" font-family=\"Helvetica\" font-size=\"12px\" text-anchor=\"middle\">Call</text></switch></g><path d=\"M 260.4 360 L 280 360 Q 290 360 300 360 L 358.48 359.99\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" stroke-dasharray=\"3 3\" pointer-events=\"stroke\"/><path d=\"M 352.6 363.49 L 359.6 359.99 L 352.6 356.49\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"all\"/><g transform=\"translate(-0.5 -0.5)\"><switch><foreignObject style=\"overflow: visible; text-align: left;\" pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"><div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 338px; margin-left: 290px;\"><div style=\"box-sizing: border-box; font-size: 0; text-align: center; \"><div style=\"display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; \">shape_call</div></div></div></foreignObject><text x=\"290\" y=\"338\" fill=\"#000000\" font-family=\"Helvetica\" font-size=\"11px\" text-anchor=\"middle\">shape_call</text></switch></g><path d=\"M 225.2 376 L 225.01 521 Q 225 531 235 531.01 L 355.78 531.15\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" stroke-dasharray=\"3 3\" pointer-events=\"stroke\"/><path d=\"M 349.9 534.65 L 356.9 531.15 L 349.91 527.65\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"all\"/><g transform=\"translate(-0.5 -0.5)\"><switch><foreignObject style=\"overflow: visible; text-align: left;\" pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"><div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 408px; margin-left: 260px;\"><div style=\"box-sizing: border-box; font-size: 0; text-align: center; \"><div style=\"display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; \">track_call_windows</div></div></div></foreignObject><text x=\"260\" y=\"408\" fill=\"#000000\" font-family=\"Helvetica\" font-size=\"11px\" text-anchor=\"middle\">track_call_wind...</text></switch></g><g transform=\"translate(-0.5 -0.5)\"><switch><foreignObject style=\"overflow: visible; text-align: left;\" pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"><div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 548px; margin-left: 280px;\"><div style=\"box-sizing: border-box; font-size: 0; text-align: center; \"><div style=\"display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; \">(Call, List[sqla.OverClause])</div></div></div></foreignObject><text x=\"280\" y=\"551\" fill=\"#000000\" font-family=\"Helvetica\" font-size=\"11px\" text-anchor=\"middle\">(Call, List[sqla.OverClause])</text></switch></g><path d=\"M 590 445 L 631.88 444.98\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/><path d=\"M 648.88 444.97 L 631.89 453.48 L 631.88 436.48 Z\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"all\"/><path d=\"M 540 299 L 540 354 Q 540 364 550 364 L 580 364 Q 590 364 590 374 L 590 441\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/><path d=\"M 540 543 L 540 525 Q 540 515 550 515 L 580 515 Q 590 515 590 505 L 590 441\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/><path d=\"M 0 247 L 0 221 L 190 221 L 190 247\" fill=\"#ffffff\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"all\"/><path d=\"M 0 247 L 0 521 L 190 521 L 190 247\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><path d=\"M 0 247 L 190 247\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><g fill=\"#000000\" font-family=\"Helvetica\" font-weight=\"bold\" text-anchor=\"middle\" font-size=\"12px\"><text x=\"94.5\" y=\"238.5\">SqlTbl</text></g><g fill=\"#000000\" font-family=\"Helvetica\" clip-path=\"url(#mx-clip-4-252-182-174-0)\" font-size=\"12px\"><text x=\"5.5\" y=\"264.5\">source: sqla.Engine</text><text x=\"5.5\" y=\"278.5\">funcs: Dict</text><text x=\"5.5\" y=\"292.5\">tbl: sql.Table</text><text x=\"5.5\" y=\"306.5\">ops: List[sqla.Select]</text><text x=\"5.5\" y=\"320.5\">group_by: Tuple</text><text x=\"5.5\" y=\"334.5\">order_by: Tuple</text><text x=\"5.5\" y=\"348.5\">/last_op: Select</text><text x=\"5.5\" y=\"362.5\">-- passed to CallTreeLocal</text><text x=\"5.5\" y=\"376.5\">rm_attr</text><text x=\"5.5\" y=\"390.5\">call_sub_attr</text><text x=\"5.5\" y=\"404.5\">dispatch_cls</text><text x=\"5.5\" y=\"418.5\">result_cls</text></g><path d=\"M 0 425 L 190 425\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><g fill=\"#000000\" font-family=\"Helvetica\" clip-path=\"url(#mx-clip-4-434-182-92-0)\" font-size=\"12px\"><text x=\"5.5\" y=\"446.5\">append_op(Select, ...) : SqlTbl</text><text x=\"5.5\" y=\"460.5\">copy(**kwargs): SqlTbl</text><text x=\"5.5\" y=\"474.5\">shape_call(Call, ...) : Call</text><text x=\"5.5\" y=\"488.5\">track_call_windows(Call):  </text><text x=\"5.5\" y=\"502.5\">get_ordered_col_names()</text></g><path d=\"M 360 501 L 360 475 L 540 475 L 540 501\" fill=\"#ffffff\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><path d=\"M 360 501 L 360 619 L 540 619 L 540 501\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><path d=\"M 360 501 L 540 501\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><g fill=\"#000000\" font-family=\"Helvetica\" font-weight=\"bold\" text-anchor=\"middle\" font-size=\"12px\"><text x=\"449.5\" y=\"492.5\">WindowReplacer</text></g><g fill=\"#000000\" font-family=\"Helvetica\" clip-path=\"url(#mx-clip-364-506-172-84-0)\" font-size=\"12px\"><text x=\"365.5\" y=\"518.5\">columns: Mapping[sqla.Column]</text><text x=\"365.5\" y=\"532.5\">group_by</text><text x=\"365.5\" y=\"546.5\">order_by</text><text x=\"365.5\" y=\"560.5\">window_cte</text><text x=\"365.5\" y=\"574.5\">windows: List</text></g><path d=\"M 360 589 L 540 589\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><g fill=\"#000000\" font-family=\"Helvetica\" clip-path=\"url(#mx-clip-364-598-172-26-0)\" font-size=\"12px\"><text x=\"365.5\" y=\"610.5\">+ method(type): type</text></g><path d=\"M 360 257 L 360 231 L 540 231 L 540 257\" fill=\"#ffffff\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><path d=\"M 360 257 L 360 431 L 540 431 L 540 257\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><path d=\"M 360 257 L 540 257\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><g fill=\"#000000\" font-family=\"Helvetica\" font-weight=\"bold\" text-anchor=\"middle\" font-size=\"12px\"><text x=\"449.5\" y=\"248.5\">CallTreeLocal</text></g><g fill=\"#000000\" font-family=\"Helvetica\" clip-path=\"url(#mx-clip-364-262-172-84-0)\" font-size=\"12px\"><text x=\"365.5\" y=\"274.5\">local: dict</text><text x=\"365.5\" y=\"288.5\">call_sub_attr: set</text><text x=\"365.5\" y=\"302.5\">chain_sub_attr: Bool</text><text x=\"365.5\" y=\"316.5\">dispatch_cls: Type</text><text x=\"365.5\" y=\"330.5\">result_cls: Type</text></g><path d=\"M 360 345 L 540 345\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><g fill=\"#000000\" font-family=\"Helvetica\" clip-path=\"url(#mx-clip-364-354-172-82-0)\" font-size=\"12px\"><text x=\"365.5\" y=\"366.5\">create_local_call(str, ...) : Call</text></g><path d=\"M 650 370 L 650 344 L 810 344 L 810 370\" fill=\"#ffffff\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><path d=\"M 650 370 L 650 574 L 810 574 L 810 370\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><path d=\"M 650 370 L 810 370\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><g fill=\"#000000\" font-family=\"Helvetica\" font-weight=\"bold\" text-anchor=\"middle\" font-size=\"12px\"><text x=\"729.5\" y=\"361.5\">CallListener</text></g><g fill=\"#000000\" font-family=\"Helvetica\" clip-path=\"url(#mx-clip-654-375-152-26-0)\" font-size=\"12px\"><text x=\"655.5\" y=\"387.5\">generic_visit: type</text></g><path d=\"M 650 400 L 810 400\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><g fill=\"#000000\" font-family=\"Helvetica\" clip-path=\"url(#mx-clip-654-409-152-170-0)\" font-size=\"12px\"><text x=\"655.5\" y=\"421.5\">enter(Call): Call</text><text x=\"655.5\" y=\"435.5\">exit   (Call): Call</text><text x=\"655.5\" y=\"449.5\">generic_enter(Call): Call</text><text x=\"655.5\" y=\"463.5\">generic_exit   (Call): Call</text><text x=\"655.5\" y=\"477.5\">enter_if_call(T): T</text><text x=\"655.5\" y=\"505.5\">-- enter, exit methods format</text><text x=\"655.5\" y=\"519.5\">enter_&lt;Call.func&gt;(Call)</text><text x=\"655.5\" y=\"547.5\">-- eg</text><text x=\"655.5\" y=\"561.5\">enter___get_item__(Call)</text></g><rect x=\"170\" y=\"51\" width=\"110\" height=\"30\" fill=\"#ffffff\" stroke=\"#000000\" pointer-events=\"none\"/><g transform=\"translate(-0.5 -0.5)\"><switch><foreignObject style=\"overflow: visible; text-align: left;\" pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"><div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 66px; margin-left: 225px;\"><div style=\"box-sizing: border-box; font-size: 0; text-align: center; \"><div style=\"display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; \">group_by(...)</div></div></div></foreignObject><text x=\"225\" y=\"70\" fill=\"#000000\" font-family=\"Helvetica\" font-size=\"12px\" text-anchor=\"middle\">group_by(...)</text></switch></g><rect x=\"340\" y=\"51\" width=\"110\" height=\"30\" fill=\"#ffffff\" stroke=\"#000000\" pointer-events=\"none\"/><g transform=\"translate(-0.5 -0.5)\"><switch><foreignObject style=\"overflow: visible; text-align: left;\" pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"><div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 66px; margin-left: 395px;\"><div style=\"box-sizing: border-box; font-size: 0; text-align: center; \"><div style=\"display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; \">arrange(...)</div></div></div></foreignObject><text x=\"395\" y=\"70\" fill=\"#000000\" font-family=\"Helvetica\" font-size=\"12px\" text-anchor=\"middle\">arrange(...)</text></switch></g><rect x=\"520\" y=\"51\" width=\"150\" height=\"30\" fill=\"#ffffff\" stroke=\"#000000\" pointer-events=\"none\"/><g transform=\"translate(-0.5 -0.5)\"><switch><foreignObject style=\"overflow: visible; text-align: left;\" pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"><div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 66px; margin-left: 595px;\"><div style=\"box-sizing: border-box; font-size: 0; text-align: center; \"><div style=\"display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; \">mutate/filter/summarize(...)</div></div></div></foreignObject><text x=\"595\" y=\"70\" fill=\"#000000\" font-family=\"Helvetica\" font-size=\"12px\" text-anchor=\"middle\">mutate/filter/summarize(....</text></switch></g><path d=\"M 225 81 L 225 121 Q 225 131 215 131 L 105 131 Q 95 131 95 141 L 95 218.76\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><path d=\"M 91.5 212.88 L 95 219.88 L 98.5 212.88\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><g transform=\"translate(-0.5 -0.5)\"><switch><foreignObject style=\"overflow: visible; text-align: left;\" pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"><div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 108px; margin-left: 150px;\"><div style=\"box-sizing: border-box; font-size: 0; text-align: center; \"><div style=\"display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; \">copy(group_by = Tuple[str])</div></div></div></foreignObject><text x=\"150\" y=\"108\" fill=\"#000000\" font-family=\"Helvetica\" font-size=\"11px\" text-anchor=\"middle\">copy(group_by =...</text></switch></g><path d=\"M 395 81 L 395 121 Q 395 131 385 131 L 105 131 Q 95 131 95 141 L 95 218.76\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><path d=\"M 91.5 212.88 L 95 219.88 L 98.5 212.88\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><g transform=\"translate(-0.5 -0.5)\"><switch><foreignObject style=\"overflow: visible; text-align: left;\" pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"><div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 108px; margin-left: 350px;\"><div style=\"box-sizing: border-box; font-size: 0; text-align: center; \"><div style=\"display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; \">copy(order_by = Tuple[sqla.Clause])</div></div></div></foreignObject><text x=\"350\" y=\"108\" fill=\"#000000\" font-family=\"Helvetica\" font-size=\"11px\" text-anchor=\"middle\">copy(order_by =...</text></switch></g><path d=\"M 595 81 L 595 121 Q 595 131 585 131 L 105 131 Q 95 131 95 141 L 95 218.76\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><path d=\"M 91.5 212.88 L 95 219.88 L 98.5 212.88\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><g transform=\"translate(-0.5 -0.5)\"><switch><foreignObject style=\"overflow: visible; text-align: left;\" pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"><div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 108px; margin-left: 550px;\"><div style=\"box-sizing: border-box; font-size: 0; text-align: center; \"><div style=\"display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: #ffffff; white-space: nowrap; \">append_op(...)</div></div></div></foreignObject><text x=\"550\" y=\"108\" fill=\"#000000\" font-family=\"Helvetica\" font-size=\"11px\" text-anchor=\"middle\">append_op(...)</text></switch></g><g transform=\"translate(-0.5 -0.5)\"><switch><foreignObject style=\"overflow: visible; text-align: left;\" pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"><div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 12px; margin-left: 410px;\"><div style=\"box-sizing: border-box; font-size: 0; text-align: center; \"><div style=\"display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; \"><font style=\"font-size: 20px\">SQL Architecture</font></div></div></div></foreignObject><text x=\"410\" y=\"16\" fill=\"#000000\" font-family=\"Helvetica\" font-size=\"12px\" text-anchor=\"middle\">SQL Architecture</text></switch></g><path d=\"M 700 151 L 786 151 L 800 165 L 800 221 L 700 221 L 700 151 Z\" fill=\"#ffffff\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><path d=\"M 786 151 L 786 165 L 800 165\" fill=\"none\" stroke=\"#000000\" stroke-miterlimit=\"10\" pointer-events=\"none\"/><g transform=\"translate(-0.5 -0.5)\"><switch><foreignObject style=\"overflow: visible; text-align: left;\" pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"><div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 98px; height: 1px; padding-top: 152px; margin-left: 702px;\"><div style=\"box-sizing: border-box; font-size: 0; text-align: left; \"><div style=\"display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; \">Note<br /><br />sqla = sqlachemy</div></div></div></foreignObject><text x=\"702\" y=\"164\" fill=\"#000000\" font-family=\"Helvetica\" font-size=\"12px\">Note...</text></switch></g></g><switch><g requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"/><a transform=\"translate(0,-5)\" xlink:href=\"https://desk.draw.io/support/solutions/articles/16000042487\" target=\"_blank\"><text text-anchor=\"middle\" font-size=\"10px\" x=\"50%\" y=\"100%\">Viewer does not support full SVG 1.1</text></a></switch></svg>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The SQL implementation consists largely of the following:\n",
    "    \n",
    "* **LazyTbl** - a class that holds a sqlalchemy connection, table name, and list of select statements.\n",
    "* **Verbs** that dispatch on LazyTbl - eg. mutate takes a LazyTbl, and returns a LazyTbl that has a new select statement corresponding to that mutate.\n",
    "* **CallListeners** for (1) translating lazy expressions to SQL specific functions, and (2) adding grouping information to OVER clauses.\n",
    "\n",
    "See TODO link this ADR for more details."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
